package cn.airfei.aircore.core.config;

import cn.airfei.aircore.core.extend.InsertLogToMongoDb;
import cn.airfei.aircore.core.extend.ParseHeaderAuthorization;
import cn.airfei.aircore.core.properties.AirCoreProperty;
import cn.airfei.aircore.core.storage.Pojo.LogForMongoDbPojo;
import com.alibaba.fastjson.JSON;
import feign.*;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FeignLoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;


/**
 * @description:
 * @author: air
 * @create: 2020-11-10 15:31
 */
@Configuration
public class FeignClientConfig {
    @Resource
    private AirCoreProperty airCoreProperty;

    @Resource
    private InsertLogToMongoDb insertLogToMongoDb;

    @Resource
    private ParseHeaderAuthorization parseHeaderAuthorization;

    /**
     * 日志级别
     *
     * @return
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }


    @Bean
    public RequestInterceptor headerInterceptor() {
        return requestTemplate -> {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                String traceId = String.valueOf(request.getAttribute("traceId"));
                requestTemplate.header("traceId", traceId);
                if (requestTemplate.headers().get("Authorization") == null && !StringUtils.isEmpty(request.getHeader("Authorization"))) {
                    requestTemplate.header("Authorization", request.getHeader("Authorization"));
                }
                if (requestTemplate.headers().get("token") == null && !StringUtils.isEmpty(request.getHeader("token"))) {
                    requestTemplate.header("token", request.getHeader("token"));
                }

                // 分页参数处理
                if (request.getParameter("pageSize") != null) {
                    requestTemplate.query("pageSize", request.getParameter("pageSize"));
                }
                if (request.getParameter("pageCurrent") != null) {
                    requestTemplate.query("pageCurrent", request.getParameter("pageCurrent"));
                }

                Map<String, Object> paraMap = new HashMap<>();
                if (requestTemplate.body() != null) {
                    paraMap.put("paramBody", new String(requestTemplate.body()));
                }
                paraMap.put("paramPath", requestTemplate.queries());

                // 写入日志
                if (airCoreProperty.getSetLogToMongoDb()) {
                    LogForMongoDbPojo logForMongoDbPojo = new LogForMongoDbPojo();
                    logForMongoDbPojo.setCreateTime(LocalDateTime.now());
                    logForMongoDbPojo.setUrl(requestTemplate.feignTarget().url() + requestTemplate.url());
                    logForMongoDbPojo.setTraceId(traceId);
                    logForMongoDbPojo.setMethod(requestTemplate.method());
                    logForMongoDbPojo.setParams(paraMap);
                    logForMongoDbPojo.setRemark("feign request");
                    logForMongoDbPojo.setToken(request.getHeader("token"));
                    logForMongoDbPojo.setAuthorization(request.getHeader("Authorization"));
                    parseHeaderAuthorization.setLoginInfo(logForMongoDbPojo);
                    insertLogToMongoDb.insertLog(logForMongoDbPojo);
                }
            }
        };
    }

    @Bean
    public FeignResultDecoder feignResultDecoder() {
        return new FeignResultDecoder();
    }


    @Bean
    FeignLoggerFactory infoFeignLoggerFactory() {
        return new FeignLoggerFactoryImpl();
    }

    private static class FeignLoggerFactoryImpl implements FeignLoggerFactory {
        @Override
        public Logger create(Class<?> type) {
            return new InfoFeignLogger(LoggerFactory.getLogger(type));
        }
    }

    private static class InfoFeignLogger extends Logger {
        private org.slf4j.Logger logger;

        public InfoFeignLogger(org.slf4j.Logger logger) {
            this.logger = logger;
        }

        @Override
        protected void log(String configKey, String format, Object... objects) {
            if (logger.isInfoEnabled()) {
                String str = String.format(methodTag(configKey) + format, objects);
                logger.info(str);
            }
        }
    }


    /**
     * feign 返回值处理
     */
    public class FeignResultDecoder implements Decoder {
        @Override
        public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
            Response.Body body = response.body();
            String bodyStr = Util.toString(body.asReader(Util.UTF_8));
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                if (airCoreProperty.getSetLogToMongoDb()) {
                    LogForMongoDbPojo logForMongoDbPojo = new LogForMongoDbPojo();
                    logForMongoDbPojo.setCreateTime(LocalDateTime.now());
                    logForMongoDbPojo.setUrl(response.request().url());
                    logForMongoDbPojo.setTraceId(String.valueOf(request.getAttribute("traceId")));
                    logForMongoDbPojo.setMethod(String.valueOf(response.request().httpMethod()));
                    logForMongoDbPojo.setResult(JSON.parseObject(bodyStr, type));
                    logForMongoDbPojo.setRemark("feign result");
                    logForMongoDbPojo.setToken(request.getHeader("token"));
                    logForMongoDbPojo.setAuthorization(request.getHeader("Authorization"));
                    parseHeaderAuthorization.setLoginInfo(logForMongoDbPojo);
                    insertLogToMongoDb.insertLog(logForMongoDbPojo);
                }
            }
            if (String.class.equals(type)) {
                return bodyStr;
            }
            return JSON.parseObject(bodyStr, type);
        }
    }
}



